package com.tpl.core.basedata.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.tpl.core.JsonUtil;
import com.tpl.core.basedata.common.constant.ICacheConstants;
import com.tpl.core.basedata.dao.*;
import com.tpl.core.basedata.service.AuthService;
import com.tpl.core.common.DateUtil;
import com.tpl.core.common.MD5;
import com.tpl.core.common.constant.IConstants;
import com.tpl.core.common.exception.RuleException;
import com.tpl.core.common.redis.RedisClientUtil;
import com.tpl.core.dao.ExecuteSql;
import com.tpl.core.entity.SessionUser;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tpl.core.entity.sys.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;


public class AuthServiceImpl implements AuthService {
	private Log log=LogFactory.getLog(AuthServiceImpl.class);
	@Autowired
	private MenuDao menuDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private DeptDao deptDao;
	@Autowired
	private RoleDao roleDao;
	@Autowired
	private LockDao lockDao;
	@Autowired
	private OperatorLogDao operatorLogDao;


	@Override
	public List<Menu> getMenu(String key, SessionUser user) {
		Long userId=user.getId();
		Long deptId=user.getDept().getId();
		boolean adminFlag=user.isAdmin();
		Object roles=getUserRole(userId, deptId, adminFlag);
		Set<Menu> menus=getUserMenu(roles, adminFlag);
		List<Menu> list=new ArrayList<Menu>();
		for(Menu menu : menus){
			if(ICacheConstants.KEY_AUTH_DEPT.equals(key))
				list.add(menu);
			else if(ICacheConstants.KEY_AUTH_DEPT_MENU.equals(key)&&(Integer.valueOf(menu.getMenuType())<2))
				list.add(menu);
			else if(ICacheConstants.KEY_AUTH_DEPT_MENU_TOP.equals(key)&&ICacheConstants.MENU_TREE_ROOT_ID.equals(menu.getParentId()))
				list.add(menu);
		}
		Collections.sort(list, 	new Comparator<Menu>() {
			@Override
			public int compare(Menu o1, Menu o2) {
				return o1.getOrderNum().equals(o2.getOrderNum())?0:(o1.getOrderNum()>o2.getOrderNum()?1:-1);
			}
		});
		//Collections.sort(list,(a, b) -> b.getOrderNum()>a.getOrderNum()?1:0);
		return list;
	}

	@Override
	public  void doWriteOperatorLog(Menu menu, SessionUser user, String ip, Integer type) {
		SystemOperateLog opLog=new SystemOperateLog();
		if(menu.getId()!=null)
			menu.setMenuName(getMenuName(menu.getId()));
		opLog.setMenuName(menu.getMenuName());
		opLog.setMenuUrl(menu.getMenuUrl());
		opLog.setOperator(user.getUserNo());
		opLog.setOperatorDate(DateUtil.getNowDateTime());
		opLog.setIp(ip);
		opLog.setMenuNo(menu.getMenuNo());
		operatorLogDao.insertLog(opLog);
	}
	/**
	 *
	 * 说明 :获取菜单全名
	 */
	private String getMenuName(Long id) {
		List<Menu> list=menuDao.getMenuFullName(id);
		String rel="";
		if(list!=null){
			for(Menu m : list){
				rel+=(StringUtils.isEmpty(rel)?"":">>")+m.getMenuName();
			}
		}
		return rel;
	}
	/**
	 *
	 * 说明 :获取菜单全名
	 */
	public List<Menu> doGetMenuName(String menuNo) {
		Menu menu=menuDao.getMenuByMenuNo(menuNo);
		List<Menu> list=menuDao.getMenuFullName(menu.getId());

		return list;
	}
	@Override
	public SessionUser doLogin(User user) {
		String md5Pwd= MD5.getMD5Str(user.getPassword());
		user=userDao.getUserByUserNo(user.getUserNo());
		if (user != null && StringUtils.equals(md5Pwd, user.getPassword())) {
//			if(user.getState()==0)
//				throw new RuleException("用户已经被禁用,请联系管理员开启！");

			if(user.getDeleted())
				throw new RuleException("用户名或密码错误");
			SessionUser suser=SessionUser.getInstance(user);
			suser.setDept(new Dept());
			initAuth(suser);
//			Menu menu=new Menu();
//			menu.setMenuName("登录");
//			String ip=IPUtil.getRealIpAddr(IPUtil.getIpAddr(ServletActionContext.getRequest()));
//			doWriteOperatorLog(menu,suser,ip,0);
			return suser;
		}else {
			throw new RuleException("用户名或密码错误");
		}
	}
	private void initAuth(SessionUser user){
		boolean adminFlag=user.isAdmin();
		JSONArray ja=getUserDept(user.getId(), adminFlag);
		int curDeptIndex=0;
		for(int i=0,len=ja.size();i<len;i++){
			JSONObject jo=ja.getJSONObject(i);
			if("1".equals(jo.getString("defaultFlag"))){
				curDeptIndex=i;
				break;
			}
		}
		Object roles=null;
		if(ja.size()>0){
			JSONObject jo=ja.getJSONObject(curDeptIndex);
			user.getDept().setId(jo.getLong("id"));
			user.getDept().setDeptName(jo.getString("deptName"));
			user.getDept().setParentId(jo.getLong("parentId"));
			user.getDept().setDeptNo(jo.getString("deptNo"));
			roles=getUserRole(user.getId(),user.getDept().getId(), adminFlag);
		}
		getUserMenu(roles, adminFlag);
	}
	/**
	 *
	 * 说明 :获取用户当前部门下的所有角色
	 */
	private Object getUserRole(Long userId,Long deptId, boolean adminFlag){
		if(adminFlag)return null;
		String key=ICacheConstants.CACHE_AUTH_USER_ROLE+deptId+"#"+userId;
		Object deptInfo = RedisClientUtil.getList(key,Role.class);
		if(deptInfo!=null)return deptInfo;
		List<Role> roles=roleDao.getUserRoles(userId, deptId);
		RedisClientUtil.addList(key, roles,ICacheConstants.AUTH_CACHE_TIME);
		return roles;
	}

	/**
	 *
	 * 说明 :获取 角色下的菜单
	 */
	private List<Menu> getRoleMenu(String roleId,boolean adminFlag){
		List<Menu> list = null;//(List<Menu>) RedisClientUtil.getList(ICacheConstants.CACHE_AUTH_ROLE_MENU+(adminFlag?"":roleId),Menu.class);
		if(list==null){
			list=menuDao.getMenu(adminFlag?null:Long.valueOf(roleId));
			RedisClientUtil.addList(ICacheConstants.CACHE_AUTH_ROLE_MENU+(adminFlag?"":roleId),list,ICacheConstants.AUTH_CACHE_TIME);
		}
		return list;
	}
	/**
	 *
	 * 说明 :用户能访问的所有菜单
	 */
	private Set<Menu> getUserMenu(Object roles, boolean adminFlag){
		Set<Menu> sets=new HashSet<Menu>();
		if(adminFlag){
			Collections.addAll(sets,getRoleMenu(null, adminFlag).toArray(new Menu[0]));
		}else{
			if(roles==null)return sets;
//			String[] roleArr=String.valueOf(roles).split(",");
			List<Role> roleArr=(List<Role>) roles;
			for(int i=0,len=roleArr.size();i<len;i++){
//				String role=roleArr[i];
				Role _role=roleArr.get(i);
				String role=((_role.isTheDefault()&&_role.getQuoteRoleId()!=null)?_role.getQuoteRoleId():_role.getId()).toString();
				if(StringUtils.isNotEmpty(role))
					Collections.addAll(sets,getRoleMenu(role, adminFlag).toArray(new Menu[0]));
			}
			Collections.addAll(sets,menuDao.getMenusByType(3L).toArray(new Menu[0]));
		}
		return sets;
	}
	/**
	 *
	 * 说明 :用户所有部门信息
	 */
	private JSONArray getUserDept(Long userId, boolean adminFlag){
		String key=ICacheConstants.CACHE_AUTH_USER_DEPT+userId;
		Object deptInfo=RedisClientUtil.getString(key);
		if(!adminFlag&&deptInfo!=null)return JSONArray.parseArray(deptInfo.toString());
		List<Dept> list=deptDao.getDepts(adminFlag?null:userId, null,null);
		JSONArray ja= JsonUtil.toJSONArray(list);
		RedisClientUtil.set(key, ja.toString(),ICacheConstants.AUTH_CACHE_TIME);
		return ja;
	}

	public void doChangePwd(User user,String newPwd){
		String oldPwdMd5=MD5.getMD5Str(user.getPassword());
		Object oldPwd= ExecuteSql.getSingleResult("select 1 from Sys_User s where s.id=? and s.password=?", user.getId(),oldPwdMd5);
		if(oldPwd==null)
			throw new RuleException("你输入的原密码不正确,请重新输入!");
		String newPwdMd5=MD5.getMD5Str(newPwd);
		ExecuteSql.execute("update Sys_User set password=? where id=?", newPwdMd5,user.getId());
	}

	@Override
	public JSONArray getUserDept(SessionUser user) {
		return getUserDept(user.getId(),user.isAdmin());
	}

	@Override
	public void changeDefaultDept(Long deptId, Long userId) {
		ExecuteSql.execute("update SYS_DEPT_RE_USER set DEFAULT_FLAG=0 where user_id=?", userId);
		ExecuteSql.execute("update SYS_DEPT_RE_USER set DEFAULT_FLAG=1 where user_id=? and dept_id=?", userId,deptId);
		RedisClientUtil.delkeyObject(ICacheConstants.CACHE_AUTH_USER_DEPT+userId);

	}

	@Override
	public JSONObject getMenuLock(String menuNo) {
		if(!IConstants.MENU_LOCK_OPEN)return null;
		Lock lock = lockDao.getMenuLock(menuNo);
		return lock==null?null: JsonUtil.toJSONObject(lock);
	}

	@Override
	public void saveMenuLock(Long id, String menuNo, String userNo,String userName,String curDate, Integer lockType) {
		if(!IConstants.MENU_LOCK_OPEN)return;
		Lock lock = new Lock();
		lock.setLockDate(curDate);
		lock.setMenuNo(menuNo);
		lock.setUserName(userName);
		lock.setUserNo(userNo);
		lock.setConstraint(true);
		lock.setLockType(lockType);
		if(id!=null){
			lockDao.updateLock(lock);
		}else{
			lockDao.insertLock(lock);
		}
	}

	@Override
	public void removeLock(String userNo,String menuNo) {
		if(!IConstants.MENU_LOCK_OPEN)return;
		//清除所有的锁
		if(StringUtils.isEmpty(menuNo)){
			lockDao.delAllLock(userNo);
		}else{
			lockDao.delOtherLock(userNo, menuNo);
		}
	}

	@Override
	public void downLock(String menuNo, String curDate) {
		if(!IConstants.MENU_LOCK_OPEN)return;
		ExecuteSql.execute("update db_lock l set l.`constraint`=0 ,l.lock_date=? where l.menu_no=?",curDate,menuNo);
	}

	@Override
	public Boolean checkAuth(String appId, String secret, String ip, String url) {
		String authIdSql="SELECT ip,id FROM `sm_accredit` where sys_key=? and ask_key=? and deleted=0 and state=1";
		List<Object[]> rels=ExecuteSql.getFields( authIdSql, appId,secret);
		if(rels!=null&&rels.size()>0){
			Object[] rel=rels.get(0);
			String allowIp=String.valueOf(rel[0]);
			if(StringUtils.isEmpty(allowIp)||(","+allowIp+",").indexOf(","+ip+",")!=-1){
				boolean check= checkInteface(Long.valueOf(rel[1].toString()),url);
				if(!check)
					log.info("您的授权["+appId+"]没有权限访问该接口:"+url);
				return check;
			}
			log.info("您所在的服务器没有权限访问系统:"+ip);
		}

		return false;
	}

	private boolean checkInteface(Long id, String url) {
		//if(true)return true;
		String sql="select 1 from sm_interfaceaccr i\n" +
				"left join sm_interfacemanager im on im.interface_id=i.id\n" +
				"where i.deleted=0 and i.state=1 and (i.type=0 or(im.deleted=0 and im.state=1 and im.system_id=? and im.open_begin_date<=? \n" +
				"and IF(im.open_end_date='' or im.open_end_date=null,'9999-99-99',im.open_end_date)>=?\n" +
				")) and INSTR(?,url)>0";
		String now= DateUtil.getNowDate("yyyy-MM-dd");
		Object rel=ExecuteSql.getSingleResult(sql, id,now,now,url);
		if(rel!=null){
			return true;
		}
		return false;
	}

	public List<Menu> getAllOperator() {
		return null;
	}

	@Override
	public List<Role> getOwnerRoles(Long userId) {
		return null;
	}

	@Override
	public Map<Long, List<Menu>> getRoleReMenu() {
		return null;
	}

	@Override
	public void removeLock(String userNo, Object object) {

	}

}
